﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Script.Serialization;

namespace Cherry.Agile.Mvc
{
    public delegate void SelfApplicable<T>(SelfApplicable<T> self, T arg);

    public static class Helper
    {

        private static IDictionary<string, int> controllerToProductIdMap = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
            {
                { "grid", 718 },
                { "menu", 719 },
                { "panelbar", 720 },
                { "tabstrip", 721 }
            };

        public static string GetCurrentTheme(this HtmlHelper html)
        {
            return html.ViewContext.HttpContext.Request.QueryString["theme"] ?? "vista";
        }


        public static string ToJSON(this object obj)
        {
            var serializer = new JavaScriptSerializer();
            serializer.RegisterConverters(new JavaScriptConverter[] { new NullPropertiesConverter() });
            return serializer.Serialize(obj);
        }

        public static string ToJSON(this object obj, int recursionDepth)
        {
            var serializer = new JavaScriptSerializer();
            serializer.RegisterConverters(new JavaScriptConverter[] { new NullPropertiesConverter() });
            serializer.RecursionLimit = recursionDepth;
            return serializer.Serialize(obj);
        }

        //public static XGridView Grid(this HtmlHelper helper, string id)
        //{
        //    return new XGridView(id);
        //}

        public static void Render<T>(this HtmlHelper helper, T model, SelfApplicable<T> f)
        {
            f(f, model);
        }

        //public static ViewComponentFactory Agile(this HtmlHelper helper)
        //{
        //    Guard.IsNotNull(helper, "helper");
        //    ViewContext viewContext = helper.ViewContext;
        //    HttpContextBase httpContext = viewContext.HttpContext;

        //    ScriptWrapperBase scriptWrapper = DI.Current.Resolve<ScriptWrapperBase>();
        //    IClientSideObjectWriterFactory clientSideObjectWriterFactory = DI.Current.Resolve<IClientSideObjectWriterFactory>();

        //    StyleSheetRegistrar styleSheetRegistrar = httpContext.Items[StyleSheetRegistrar.Key] as StyleSheetRegistrar ??
        //                                                new StyleSheetRegistrar(new WebAssetCollection(WebAssetDefaultSettings.StyleSheetFilesPath), viewContext, DI.Current.Resolve<IWebAssetCollectionResolver>());
        //    ScriptRegistrar scriptRegistrar = httpContext.Items[ScriptRegistrar.Key] as ScriptRegistrar ??
        //                                                new ScriptRegistrar(new WebAssetCollection(WebAssetDefaultSettings.ScriptFilesPath), new List<IScriptableComponent>(), viewContext, DI.Current.Resolve<IWebAssetCollectionResolver>(), scriptWrapper);

        //    StyleSheetRegistrarBuilder styleSheetRegistrarBuilder = StyleSheetRegistrarBuilder.Create(styleSheetRegistrar);
        //    ScriptRegistrarBuilder scriptRegistrarBuilder = ScriptRegistrarBuilder.Create(scriptRegistrar);

        //    return new ViewComponentFactory(helper, clientSideObjectWriterFactory, styleSheetRegistrarBuilder, scriptRegistrarBuilder);
        //}

        //public static MvcHtmlString TextBoxFor<T>(this HtmlHelper<T> htmlHelper, Expression<Func<T, uint>> expression)
        //{
        //    return htmlHelper.TextBoxFor<T>(expression, new { @class = "uint" });
        //}

        //public static MvcHtmlString TextBoxFor<T>(this HtmlHelper<T> htmlHelper, Expression<Func<T, DateTime>> expression)
        //{
        //    return htmlHelper.TextBoxFor(expression, new { @class = "date" });
        //}

        //public static MvcHtmlString TextBoxFor<T>(this HtmlHelper<T> htmlHelper, Expression<Func<T, string>> expression)
        //{
        //    return htmlHelper.TextBoxFor(expression, new { @class = "string" });
        //}

        //public static MvcHtmlString TextBoxFor<T>(this HtmlHelper<T> htmlHelper, Expression<Func<T, decimal>> expression)
        //{
        //    return htmlHelper.TextBoxFor(expression, new { @class = "rmb" });
        //}
    }

    public class NullPropertiesConverter
        : JavaScriptConverter
    {
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var propertiesToBeSerialized = new Dictionary<string, object>();
            foreach (var prop in obj.GetType().GetProperties())
            {
                var value = prop.GetValue(obj, BindingFlags.Public, null, null, null);

                if (value != null)
                {
                    propertiesToBeSerialized.Add(LowercaseFirst(prop.Name), value);
                }
            }

            return propertiesToBeSerialized;
        }

        public override IEnumerable<Type> SupportedTypes
        {
            get { return GetType().Assembly.GetTypes(); }
        }

        private string LowercaseFirst(string s)
        {
            return char.ToLower(s[0]) + s.Substring(1);
        }

    }

    //public static class HtmlHelperExtention
    //{
    //    /// <summary>
    //    /// Creates a DatePicker for the current fie
    //    /// NOTE: the element must contain an id in the following format: id="THE-ELEMENT-ID"
    //    /// </summary>
    //    /// <param name="html"></param>
    //    /// <param name="datePicker"></param>
    //    /// <returns></returns>
    //    public static string AsAutoComplete(this MvcHtmlString html, AutoComplete autoComplete)
    //    {
    //        string elemId = getIdFromString(html);
    //        return html.ToHtmlString() + autoComplete.Render(elemId);
    //    }

    //    /// <summary>
    //    /// Creates a DatePicker for the current fie
    //    /// NOTE: the element must contain an id in the following format: id="THE-ELEMENT-ID"
    //    /// </summary>
    //    /// <param name="html"></param>
    //    /// <param name="datePicker"></param>
    //    /// <returns></returns>
    //    public static string AsDatePicker(this MvcHtmlString html, DatePicker datePicker)
    //    {
    //        string elemId = getIdFromString(html);
    //        return html.ToHtmlString() + datePicker.Render(elemId);
    //    }

    //    public static string Accordion(this HtmlHelper html, AccordionControl accCtrl)
    //    {
    //        return accCtrl.Render(html);
    //    }

    //    public static string Tab(this HtmlHelper html, TabControl tabCtrl)
    //    {
    //        return tabCtrl.Render(html);
    //    }

    //    /// <summary>
    //    /// Serializes the specified model object to a GET querystring parameter
    //    /// Note: The serialization is shallow, meaning only first level properties are serialized
    //    /// </summary>
    //    /// <param name="html"></param>
    //    /// <param name="model">The model object to serialize</param>
    //    /// <param name="parameterName">The parameter name of the Controller method</param>
    //    /// <returns></returns>
    //    public static string BuildQuery(this HtmlHelper html, object model, string parameterName)
    //    {

    //        PropertyInfo[] props = model.GetType().GetProperties();
    //        StringBuilder sb = new StringBuilder();
    //        sb.Append("?");
    //        bool isFirst = true;

    //        foreach (PropertyInfo prop in props)
    //        {
    //            object val = prop.GetValue(model, null);
    //            if (val != null)
    //            {
    //                if (isFirst) isFirst = false;
    //                else sb.Append("&");
    //                sb.AppendFormat("{0}.{1}={2}", parameterName, prop.Name, val);
    //            }
    //        }

    //        return sb.ToString();
    //    }

    //    private static string getIdFromString(MvcHtmlString html)
    //    {
    //        string raw = html.ToHtmlString();
    //        if (raw.IndexOf("id=") == -1)
    //            throw new ArgumentException("MVC.Controls.DatePicker can only be used for MvcHtmlString with an html-id"
    //                + Environment.NewLine + "[" + html.ToHtmlString() + "]");

    //        raw = raw.Substring(raw.IndexOf("id=") + 4);
    //        raw = raw.Substring(0, raw.IndexOf("\""));

    //        return raw;
    //    }

    //    internal static string RenderPartialToString(HtmlHelper htmlHelper, string viewName, object viewModel, ViewDataDictionary viewData)
    //    {
    //        StringWriter sw = new StringWriter();

    //        ViewContext newViewContext = new ViewContext(htmlHelper.ViewContext.Controller.ControllerContext,
    //                                                     new FakeView(),
    //                                                     htmlHelper.ViewContext.ViewData,
    //                                                     htmlHelper.ViewContext.TempData,
    //                                                     sw);

    //        var newHelper = new HtmlHelper(newViewContext, new ViewPage());
    //        newHelper.RenderPartial(viewName, viewModel, viewData);

    //        string res = sw.ToString();
    //        sw.Close();
    //        sw.Dispose();

    //        return res;
    //    }
    //}

    internal class FakeView : IView
    {
        public void Render(ViewContext viewContext, TextWriter writer)
        {
            throw new NotImplementedException();
        }
    }
}
